package other.system.client.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.exception.ApiEntityServiceException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.model.BatchOperateResult;
import com.rkhd.platform.sdk.model.OperateResult;
import com.rkhd.platform.sdk.model.QueryResult;
import com.rkhd.platform.sdk.model.XObject;
import com.rkhd.platform.sdk.service.XObjectService;
import com.rkhd.platform.sdk.service.XoqlService;

import java.util.ArrayList;
import java.util.List;

/**
 * 功能描述：封装销售易XObjectService
 *
 * @author 范伟绵
 * @ClassName: HCXObjectService
 * @Description: 封装销售易XObjectService
 * @date 2021年12月03日
 */

public class HCXObjectService {
    private static final Logger LOGGER = LoggerFactory.getLogger();
    private static final XObjectService XOBJECTSERVICE = XObjectService.instance();
    private static XoqlService xoqlService = XoqlService.instance();
    private static boolean isLocal = false; // true 本地  false  上传paas

    ////////////////////////////////////////////////query & get ///////////////////////////////////////////////////////////////////////////////
    /*功能描述：根据查询语句获取系统记录。仅支持单表查询。（最大获取300条记录）
     * 参数sql：系统支持的查询语句。
     * 返回： 返回值为List<? extends XObject> 类型。
     */
    public <T extends XObject> List<T> query(String sql, Class<T> clazz) throws ApiEntityServiceException {
        StringBuilder sqlBuilder = new StringBuilder(sql);
        sqlBuilder.append(" limit 0,300");
        LOGGER.info("Sql:" + sqlBuilder.toString());
        QueryResult<T> result = XOBJECTSERVICE.query(sqlBuilder.toString(), true);
        if (!result.getSuccess()) {
            LOGGER.error("query:" + result.getErrorMessage());
            return null;
        }
        List<T> records = result.getRecords();
        return records;
    }

    /*功能描述：根据查询语句获取系统记录。仅支持单表查询。（最大获取1条记录）
     * 参数sql：系统支持的查询语句。
     * 返回： 返回值为<T extends XObject> T。
     */
    public <T extends XObject> T queryOne(String sql, Class<T> clazz) throws ApiEntityServiceException {
        StringBuilder sqlBuilder = new StringBuilder(sql);
        sqlBuilder.append(" limit 0,1");
        LOGGER.info("Sql:" + sqlBuilder.toString());
        QueryResult<XObject> result = XOBJECTSERVICE.query(sqlBuilder.toString(), true);
        if (!result.getSuccess()) {
            LOGGER.error("query:" + result.getErrorMessage());
            return null;
        }
        if (result.getRecords().size() <= 0) {
            return null;
        }
        return (T) result.getRecords().get(0);
    }

    /**
     * 按id批量查询
     *
     * @param apiKey
     * @param ids
     * @param <T>
     * @return
     * @throws ApiEntityServiceException
     */
    public <T extends XObject> List<T> getByIds(String apiKey, List<Long> ids) throws ApiEntityServiceException {
        LOGGER.info("ids:" + ids.toString());
        return XOBJECTSERVICE.getByIds(apiKey, ids, true);
    }

    /**
     * 按id批量查询
     *
     * @param apiKey
     * @param id
     * @param <T>
     * @return
     * @throws ApiEntityServiceException
     */
    public <T extends XObject> T getById(String apiKey, Long id) throws ApiEntityServiceException {
        LOGGER.info("is:" + id.toString());
        List<Long> ids = new ArrayList<>();
        ids.add(id);
        return (T) XOBJECTSERVICE.getByIds(apiKey, ids, true).get(0);
    }


    /*功能描述：根据查询语句获取记录总条数
     * 参数sql：系统支持的查询语句。
     * 返回： 返回值为Long类型。
     */
    public Long getCount(String sql) throws ApiEntityServiceException {
        LOGGER.info("Sql:" + sql);
        //TODO:需要修改为管理员权限
        QueryResult<XObject> result = XOBJECTSERVICE.query(sql, true);
        if (!result.getSuccess()) {
            LOGGER.error("getCount:" + result.getErrorMessage());
            return -1L;
        }
        return result.getTotalCount();
    }

    /*功能描述：根据查询语句获取系统全部记录。仅支持单表查询。
     * 参数sql：系统支持的查询语句。
     * 返回： 返回值为List<? extends XObject> 类型。
     */
    public <T extends XObject> List<T> queryAll(String sql, Class<T> clazz) throws Exception {
        List<XObject> list = new ArrayList<>();
        Long totalSize = getCount(sql);
        getMaxQuery(list, sql, 0, totalSize);
        List<T> list1 = (List<T>) list;
        return list1;
    }



    /*功能描述：递归查询最多totalSize条记录
     * 参数list：返回列表
     * 参数sql：系统支持的查询语句。
     * 参数start：起始查询位置
     * 参数totalSize：最大查询数量
     */
    private void getMaxQuery(List<XObject> list, String sql, int start, Long totalSize) throws Exception {
        int everyRunCount = 300;                        //每次获取的数量
        StringBuilder sqlBulder = new StringBuilder(sql);
        sqlBulder.append(" order by createdAt desc ");
        sqlBulder.append(" LIMIT ");
        sqlBulder.append(start + ",");
        sqlBulder.append(everyRunCount);
        LOGGER.info("sql:" + sqlBulder.toString());
        QueryResult<XObject> queryResult = XOBJECTSERVICE.query(sqlBulder.toString(), true);
        if (!queryResult.getSuccess()) {
            throw new Exception("获取CRM数据失败：" + queryResult.getErrorMessage());
        }
        if (queryResult.getSuccess() && queryResult.getRecords().size() > 0) {
            list.addAll(queryResult.getRecords());
        }
        if (queryResult.getRecords().size() == everyRunCount) {
            //只有本次查询到100条记录的情况下，才会再次查询
            if (Integer.parseInt(totalSize.toString()) > start + everyRunCount) {
                getMaxQuery(list, sql, start + everyRunCount, totalSize);
            }
        }
    }

    /*功能描述：获取单一对象
     * 参数xObject：对象
     * 返回值：完整的一个对象
     */
    public <T extends XObject> T get(T xObject) throws ApiEntityServiceException {
        T obj = XOBJECTSERVICE.get(xObject, true);
        if (null == obj || null == obj.getId()) {
            LOGGER.error("获取单一对象失败");
            return null;
        }
        return obj;
    }

    ////////////////////////////////////////////////lock & unlock ///////////////////////////////////////////////////////////////////////////////
    /*功能描述：锁定单条记录
     * 参数xObject：对象
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean lock(T xObject) throws ApiEntityServiceException {
        OperateResult result = XOBJECTSERVICE.lock(xObject, true);
        String msg = result.getSuccess() ? "锁定单条记录成功。" : "锁定单条记录失败:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }

    /*功能描述：解锁单条记录
     * 参数xObject：对象
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean unlock(T xObject) throws ApiEntityServiceException {
        OperateResult result = XOBJECTSERVICE.unlock(xObject, true);
        String msg = result.getSuccess() ? "解锁单条记录成功。" : "解锁单条记录失败:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }

    ////////////////////////////////////////////////insert///////////////////////////////////////////////////////////////////////////////
    /*功能描述：插入单条记录
     * 参数xObject：插入对象
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> OperateResult insert(T xObject) throws ApiEntityServiceException {
        OperateResult result = XOBJECTSERVICE.insert(xObject, true);
        return result;
    }

    /**
     * 兼容本地和paas平台
     *
     * @param xObjects
     * @param <T>
     * @return
     * @throws ApiEntityServiceException
     */
    public <T extends XObject> BatchOperateResult batchInsert(List<T> xObjects) throws ApiEntityServiceException {
        BatchOperateResult result = new BatchOperateResult();
        if (isLocal) {
            result.setSuccess(true);
            int size = xObjects.size();
            List<OperateResult> batchInsert = new ArrayList<>();
            for (T object : xObjects) {
                System.out.println("插入第：" + size + " 条数据");
                OperateResult insert = XOBJECTSERVICE.insert(object, true);
                if (!insert.getSuccess()) {
                    System.err.println(JSONObject.toJSONString(object));
                    System.err.println(JSONObject.toJSONString(insert));
                    result.setSuccess(insert.getSuccess());
                    result.setErrorMessage(insert.getErrorMessage());
                    result.setCode(insert.getCode());
                }
                batchInsert.add(insert);
                size--;
            }
            result.setOperateResults(batchInsert);
        } else {
            result = XOBJECTSERVICE.insert(xObjects, false, true); // partialSuccess = false 不允许部分成功
        }
        String msg = result.getSuccess() ? "插入多条记录成功。" : "插入多条记录失败:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result;
    }


    ////////////////////////////////////////////////update///////////////////////////////////////////////////////////////////////////////
    /*功能描述：更新单条记录
     * 参数xObject：更新对象
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean update(T xObject) throws ApiEntityServiceException {
        OperateResult result = XOBJECTSERVICE.update(xObject, true);
        String msg = result.getSuccess() ? "更新单条记录成功。" : "更新单条记录失败:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }

    /*功能描述：更新多条单条记录
     * 参数xObjects：更新对象列表
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean batchUpdate(List<T> xObjects) throws ApiEntityServiceException {
        BatchOperateResult result = new BatchOperateResult();
        if (isLocal) {
            result.setSuccess(true);
            List<OperateResult> batchDelete = new ArrayList<>();
            for (T object : xObjects) {
                OperateResult update = XOBJECTSERVICE.update(object, true);
                if (!update.getSuccess()) {
                    result.setSuccess(update.getSuccess());
                    result.setErrorMessage(update.getErrorMessage());
                    result.setCode(update.getCode());
                }
                batchDelete.add(update);
            }
            result.setOperateResults(batchDelete);

        } else {
            result = XOBJECTSERVICE.update(xObjects, true, true);
        }

        String msg = result.getSuccess() ? "更新多条记录成功。" : "更新多条数据错误信息:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }

    ////////////////////////////////////////////////delete///////////////////////////////////////////////////////////////////////////////
    /*功能描述：删除单条记录
     * 参数xObject：删除对象
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean delete(T xObject) throws ApiEntityServiceException {
        OperateResult result = XOBJECTSERVICE.delete(xObject, true);
        String msg = result.getSuccess() ? "删除单条记录成功。" : "删除单条数据错误信息:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }


    /*功能描述：删除多条单条记录
     * 参数xObjects：删除对象列表
     * 返回值：true(成功）；false(失败)
     */
    public <T extends XObject> Boolean batchDelete(List<T> xObjects) throws ApiEntityServiceException {
        BatchOperateResult result = new BatchOperateResult();
        if (isLocal) {
            result.setSuccess(true);
            List<OperateResult> batchDelete = new ArrayList<>();
            for (T object : xObjects) {
                OperateResult delete = XOBJECTSERVICE.delete(object, true);
                if (!delete.getSuccess()) {
                    result.setSuccess(delete.getSuccess());
                    result.setErrorMessage(delete.getErrorMessage());
                    result.setCode(delete.getCode());
                }
                batchDelete.add(delete);
            }
            result.setOperateResults(batchDelete);
        } else {
            result = XOBJECTSERVICE.delete(xObjects, true);
        }

        String msg = result.getSuccess() ? "删除多条记录成功。" : "删除多条数据错误信息:" + JSON.toJSONString(result);
        LOGGER.info(msg);
        return result.getSuccess();
    }

    /**
     * 根据sql获取所有数据
     * @param sql
     * @return
     * @throws ApiEntityServiceException
     */
    public List<JSONObject> xoqlGetAllData(String  sql) throws ApiEntityServiceException {
        List<JSONObject> dataList = new ArrayList<>();
        boolean isSearch = true;
        int startIndex = 0;
        int pageSize = 3000;
        while (isSearch) {
            String xoqlSql = String.format(sql + " limit %s offset %s", pageSize, startIndex);
            List<JSONObject> records = xoqlService.query(xoqlSql, true).getRecords();
            dataList.addAll(records);
            if (records.size() < pageSize) {
                isSearch = false;
            }
            startIndex += pageSize;
        }
        System.out.println("dataList = " + dataList.size());
        return dataList;
    }
}